#
#   api_whitepages.py
#
#   David Janes
#   2008.11.12
#
#	Copyright 2008, 2009 David Janes
#
#	Interface to WhitePages.com
#

import os
import sys
import re
import urllib
import types
import pprint
import types
import md5

import bm_extract
import bm_uri
import api
import bm_cfg

import mfdict
import vcard
import hcard

home_keyd = {
	"work" : "%s.%s" % ( vcard.Work, vcard.Voice, ),
	"home" : "%s" % ( vcard.Voice, ),
	"phone" : "%s" % ( vcard.Voice, ),
	"business" : "%s.%s" % ( vcard.Work, vcard.Voice, ),
	"government" : "%s.%s" % ( vcard.Work, vcard.Voice, ),
	"mobile" : "%s" % ( vcard.Mobile, ),
}

business_keyd = {
	"work" : "%s.%s" % ( vcard.Work, vcard.Voice, ),
	"home" : "%s.%s" % ( vcard.Home, vcard.Voice, ),
	"phone" : "%s.%s" % ( vcard.Work, vcard.Voice, ),
	"business" : "%s.%s" % ( vcard.Work, vcard.Voice, ),
	"government" : "%s.%s" % ( vcard.Work, vcard.Voice, ),
	"mobile" : "%s.%s" % ( vcard.Work, vcard.Mobile, ),
}

class FindPerson(api.APIReader):
	"""See: http://developer.whitepages.com/docs/Methods/find_person
	- firstname (required: no)
	  firstname=robert
	- lastname (required: yes)
	  see Note about required parameter lastname=johnson
	- name (required: yes)
	  see Note about required parameter name="bill%20johnson"
	- house (required: no)
	  The house parameter is the house number 	house=400
	- street (required: no)
	  the street parameter is the street name, including any directional prefix or suffix
	  street=maple%20st
	- city (required: no)
	  city=seattle
	- state (required: no)
	  USPS two-character abbreviation 	state=wa
	- zip (required: no)
	  will accept 5 digit ZIP Code or 9 digit ZIP+4 	zip=98101
	- areacode (required: no)
	  areacode=206
	- metro (required: no)
      Whether to expand the search to the metro area.
	  The default value is 0 (false) which means searches are not expanded to metro area by default.
	"""
	_uri_base = "http://api.whitepages.com/find_person/1.0/"
	_item_path = "listings.listing"
	_meta_removes = [ "listings", ]
	api_key = None
	id = None

	def __init__(self, **ad):
		api.APIReader.__init__(self, **ad)

	def CustomizeExcludeItem(self, item):
		if self.id == None:
			return

		return	self.id != item.get('id')

	def ConstructPageURI(self):
		self._uri = self._uri_base + "?"

		#
		#	Required parameters
		#
		any = False
		for key in [ "name", "firstname", "lastname", ]:
			value = self._request_meta.get(key)
			if value:
				any = True
				break

		if not any:
			raise	ValueError, "'api_key' must be explicity set or defined in 'whitepages.api_key'"

		#
		#	URL parameters, the way Whitepages likes it
		#
		for key in [ "name", "firstname", "lastname", "street", "city", "state", ]:
			value = self._request_meta.get(key)
			if value:
				self._uri += "%s=%s;" % ( key, urllib.quote(value), )

		#
		#	API Key
		#
		if not self.api_key:
			self.api_key = bm_cfg.cfg.as_string('whitepages.api_key')

		if not self.api_key:
			raise	ValueError, "'api_key' must be explicity set or defined in 'whitepages.api_key'"

		self._uri += "api_key=%s" % self.api_key

		return	self._uri
			
	def CustomizeAtomItem(self, itemd):
		ad = itemd.get('address') or {}
		hd = mfdict.mfdict()

		#
		#	Extended Address
		#
		if ad.get('apttype') and ad.get('aptnumber'):
			hd[vcard.ExtendedAddress] = "%s %s" % ( ad.get('apttype'), ad.get('aptnumber'), )

		#
		#	ZIP Code
		#
		if ad.get('zip'):
			if ad.get('zip4'):
				hd[vcard.PostalCode] = "%s-%s" % ( ad.get('zip'), ad.get('zip4'), )
			else:
				hd[vcard.PostalCode] = "%s" % ( ad.get('zip'), )

		#
		#	Name
		#
		hd[vcard.FN] = " ".join(filter(None, [ 
			bm_extract.as_string(itemd, 'people.person.firstname'),
			bm_extract.as_string(itemd, 'people.person.middlename'),
			bm_extract.as_string(itemd, 'people.person.lastname'),
		]))

		#
		#	Other keys...
		#
		for k_from, k_to, f in [
			( 'address.fullstreet', vcard.StreetAddress, None, ),
			( 'address.state', vcard.Region, None, ),
			( 'address.city', vcard.Locality, None, ),
			( 'address.country', vcard.CountryName, None, ),
			( 'geodata.latitude', vcard.Latitude, bm_extract.as_float, ),
			( 'geodata.longitude', vcard.Longitude, bm_extract.as_float, ),
			( 'business.businessname', vcard.OrganizationName, None, ),
		]:
			value = (f or bm_extract.as_string)(itemd, k_from)
			if value:
				hd[k_to] = value

		#
		#	Phone numbers...
		#

		for key, phoned in bm_extract.as_dict(itemd, 'phonenumbers').iteritems():
			value = bm_extract.as_string(phoned, 'fullphone')
			if not value:
				continue

			keyd = hd.get(vcard.OrganizationName) and business_keyd or home_keyd
			key = keyd.get(key) or vcard.Voice

			hd[key] = value

		vcard.scrub(hd)

		#
		#	Put it all together
		#
		resultd = {
			"title" : hd.get('fn') or '[No Name]',
			"hcard:hcard" : vcard.decompose(hd),
			## "o" : itemd,
		}

		#
		#	Links
		#
		for link in bm_extract.as_list(itemd, 'listingmeta.moreinfolinks.link'):
			title = None
			rel = "related"

			if link.find('FindNeighbors') > -1:
				title = "Find Neighbours"
			elif link.find('map_provider') > -1:
				title = "Map"
			elif link.find('Replay') > -1:
				title = "Whitepages.com"
				rel = "alternate"

			api.add_link(resultd, link, rel = rel, title = title, type = "text/html")

		#
		#	Make ID (hack!)
		#
		values = []
		values.append(hd.get('fn'))
		values.extend(bm_extract.as_list(itemd, 'phonenumbers//fullphone'))
		values = filter(None, values)
		values.sort()

		resultd['id'] = md5.md5("@".join(values)).hexdigest()
		resultd['content'] = vcard.as_hcard(hd)

		#
		#	Lat / Lon
		#
		if hd.find(vcard.Latitude) and hd.find(vcard.Latitude):
			api.add_latlon(resultd, hd.find(vcard.Latitude), hd.find(vcard.Latitude))

		return	resultd

if __name__ == '__main__':
	bm_cfg.cfg.initialize()

	try:
		import json
	except:
		import simplejson as json

	from bm_log import Log
	Log.verbose = True

	apio = FindPerson()
	apio.request = {
		"name" : "John Smith",
		## "id" : "40b296d1a95f3b379a8108b27daf009c",
	}
	for item in apio.items:
		pprint.pprint(item)

	## pprint.pprint(apio.response)
